package scatter.common.rest.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.util.CollectionUtils;
import scatter.common.rest.cache.CacheHelper;
import scatter.common.rest.tools.CommonSingletonTool;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 缓存相关配置
 * </p>
 *
 * @author yangwei
 * @since 2021-08-09 22:10
 */
@Slf4j
@EnableCaching
public class CommonCacheConfig {

	/**
	 * 初始化用到的cache，主要是为了在metrics中可以被监控到
	 */
	@Value("${scatter.cache:}")
	private List<String> names;

	/**
	 * 申明缓存管理器，会创建一个切面（aspect）并触发Spring缓存注解的切点（pointcut）
	 * 根据类或者方法所使用的注解以及缓存的状态，这个切面会从缓存中获取数据，将数据添加到缓存之中或者从缓存中移除某个值

	 * @return
	 */
	@Bean
	@ConditionalOnBean(RedisConnectionFactory.class)
	public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
		RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
		//使用 GenericJackson2JsonRedisSerializer 来序列化和反序列化redis的value值（默认使用JDK的序列化方式）
		GenericJackson2JsonRedisSerializer jacksonSeial = new GenericJackson2JsonRedisSerializer(CommonSingletonTool.objectMapperForRedisCacheSingleton());


		// 设置缓存管理器管理的缓存的默认过期时间
		defaultCacheConfig = defaultCacheConfig
				// 设置 key为string序列化
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(CommonSingletonTool.stringRedisSerializer()))
				// 设置value为json序列化
				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial))
				;


		Set<String> cacheNames = new HashSet<>();
		// 翻译 scatter.common.rest.trans.ITransService 中使用的两个缓存名称
		cacheNames.add("ITransBatchServiceCache");
		cacheNames.add("ITransServiceCache");
		// 额外的缓存名称
		if (CollectionUtils.isEmpty(names)) {
			log.warn("未配置初始化的缓存名称，这将导致cache监控失效，可以添加 scatter.cache.names 来配置@Cacheable 已指定的缓存名称");
		}else {
			cacheNames.addAll(names);
		}
		RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
				.cacheDefaults(defaultCacheConfig)
				// 只有在初始时设置缓存名称和下面的开户统计，才会在actuator中的prometheus里获取到监控数据
				.initialCacheNames(cacheNames)
				.enableStatistics()
				.build();
		return cacheManager;
	}

	@Bean
	private CacheHelper cacheHelper(){
		return new CacheHelper();
	}
}
